<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <button class="btn">按钮</button>

    <script>

        // Generator函数
        // Generator函数是ES6提供的一种异步编程解决方案（被async/await代替）
        // Generator函数也称为迭代器生成函数，执行后会返回一个迭代器对象
        // Generator函数内部配合yield关键字使用，yield 暂停和恢复 Generator函数 (pause and resume) 
        // yield 关键字后面的表达式的值返回给生成器的调用者，可以被认为是一个基于生成器的版本的 return 关键字。
        // Generator函数在function和函数名之间有一个*号

        // 普通函数
        function fn1() {
            console.log('普通函数执行 1');
            console.log('普通函数执行 2');
            console.log('普通函数执行 3');
            return 123;
        }
        console.log(fn1()); // 123

        // function* 这种声明方式 (function关键字后跟一个星号）会定义一个生成器函数 (generator function)，它返回一个 Generator 对象。
        // yield 关键字后面的表达式的值返回给生成器的调用者，可以被认为是一个基于生成器的版本的 return 关键字。
        function* fn2() {
            console.log('Generator函数执行 1');
            yield 123;
            console.log('Generator函数执行 2');
            yield 456;
            console.log('Generator函数执行 3');
            yield 789;
        }
        // 并不是Function对象，而是继承了Function对象的Generator对象
        console.log("fn2 object type:", Object.prototype.toString.call(fn2)); //[object GeneratorFunction]

        // 调用一个生成器函数并不会马上执行它里面的语句，而是返回一个这个生成器的 迭代器 （ iterator ）对象。
        // Generator函数，调用之后是一种暂停状态
        let res1 = fn2();
        console.log("res1 object type:", Object.prototype.toString.call(res1)); // fn2 {<suspended>} 迭代器对象

        let arr = [1, 2, 3, 4];
        console.log(arr);
        console.log("arr object type:", Object.prototype.toString.call(arr));
        // Symbol.iterator 为每一个对象定义了默认的迭代器。
        // arr[Symbol.iterator] => Generator函数对象, 只能使用[]调用
        console.log("arr[Symbol.iterator]:", Object.prototype.toString.call(arr[Symbol.iterator]));
        let iterator = arr[Symbol.iterator]();// 迭代器(Iterator)对象
        console.log("iterator:", Object.prototype.toString.call(iterator));

        document.querySelector('.btn').onclick = function () {
            // next表示产出一个值
            // value 是yield产出的值
            // done 表示产出状态
            // console.log( res1.next() );// {value: 123, done: false}

            console.log(iterator.next());
        }

        Object.prototype.hehe = '呵呵';
        let obj1 = {
            name: '小王',
            age: 26,
            sex: '女'
        }

        // for (let key in obj1){
        //     console.log( key );// name age sex hehe
        // }

        // 给obj1对象部署迭代器接口
        obj1[Symbol.iterator] = function* () {// Generator函数
            console.log('对象的迭代器接口。。。');
            // this -> obj1
            let arr = Object.keys(this);// ['name','age','sex']
            for (var i = 0; arr[i]; i++) {
                yield arr[i];
                // yield 'name';
                // yield 'age';
                // yield 'sex';

                // yield [arr[i],this[arr[i]]];
                // yield ['name','小王'];
                // yield ['age',26];
                // yield ['sex','女'];
            }
            // arr.forEach(item=>{
            //     yield [item,this[item]];// 报错，在当前函数中没有yield关键字
            //     // yield ['name','小王'];
            //     // yield ['age',26];
            //     // yield ['sex','女'];
            // })
        }
        console.log(...obj1);//  ['name', '小王'],['age', 26],['sex', '女']


    </script>
</body>

</html>